#pragma once

#include "SceneChildContext.hxx"
#include "SceneTransformationBase.hxx"

namespace Eifersucht
{
	// Prototypes

	class SkeletonContext; TinyTypeDecl( SkeletonContext );
	class MeshContext; TinyTypeDecl( MeshContext );
	class SceneChild; TinyTypeDecl( SceneChild );
	class Scene; TinyTypeDecl( Scene );

	// Implementation

	class MeshContext : public SceneChildContext
	{
		// Defines the MeshContext internal implementation and all the Fbx library interop.
		struct _Internal_impl; typedef _Internal_impl Impl; TinyTypeDecl( Impl );
		friend _Internal_impl;
		friend SceneChild;
		friend Scene;

	public: // Internal shared type definitions

		typedef UInt32 UInt32x1; // Unsigned int
		struct Bone; TinyTypeDecl( Bone ); // Link
		struct Skin; TinyTypeDecl( Skin ); // Skin deformer
		struct Deformation; TinyTypeDecl( Deformation ); // Deformation
		struct Tripoly; TinyTypeDecl( Tripoly ); // Face
		struct Texture; TinyTypeDecl( Texture ); // Texture data
		struct ControlPoint; TinyTypeDecl( ControlPoint ); // Control point
		struct Skin; TinyTypeDecl( Skin ); // Skin deformer
		typedef std::vector<BonePtr> BoneCollection; TinyTypeDecl( BoneCollection ); // Link vector
		typedef std::vector<SkinPtr> SkinCollection; TinyTypeDecl( SkinCollection ); // Skin deformer vector
		typedef std::vector<Tripoly> TripolyCollection; TinyTypeDecl( TripolyCollection ); // Polygon vector
		typedef std::vector<ControlPoint> ControlPointCollection; TinyTypeDecl( ControlPointCollection ); // Control point vector
		typedef Float32 Float32x1; TinyTypeDecl( Float32x1 ); // float x 1 (align4)
		typedef Reign::Vector2 Float32x2; TinyTypeDecl( Float32x2 ); // float x 2 (align8)
		typedef Reign::Vector4 Float32x4; TinyTypeDecl( Float32x4 ); // float x 4 (align16)
		typedef std::multimap<UInt32, Float32x2> TexCoordMap; // Texture id <> Texture coords 
		typedef std::map<UInt32x1, Texture> TexMap; // Texture id <> Texture data 
		typedef std::vector<UInt32x1> UInt32Collection; TinyTypeDecl( UInt32Collection ); // Unsigned int vector
		typedef std::vector<Float32x1> Float32Collection; TinyTypeDecl( UInt32Collection ); // Float vector

		struct ControlPoint // Control point
		{
			UInt32x1 u1Id; // Control Points Id 
			Float32x4 f4Position; // Control Point Position
		};

		/// Only triangulated mesh is supported 

		struct Tripoly						// Face
		{
			UInt32x1 u1Id;					// Poly id 
			UInt32x1 u1GroupId;				// Polygroup id 
			UInt32x1 v3u1ControlPoints[3];	// Control point ids
			Float32x4 v3f4Colors[3];		// Control point colors
			Float32x4 v3f4Normals[3];		// Control point normals
			Float32x4 v3f4Binormals[3];		// Control point binormals
			Float32x4 v3f4Tangents[3];		// Control point tangents
			//TexCoordMap vnu1f2Tex;		// Texture coords mapping
			Float32x2 v3f2TexCoords[3];		// Texture coords
		};

		struct Texture						// Texture data
		{
			UInt32 u1Id;					// Texture Id 
			String16 wszFile;				// Texture file
		};

		struct Bone
		{
			uint32 uSize;				// Bone id
			float32 *pWeights;			// Control point weights
			uint32 *pIndices;			// Control point indices

			SkeletonContextPtr pSkeleton;
			SkinPtr pSkin;

			// Associated node transform
			TransformationBasePtr pChildTranformation;	

			Bone();
			~Bone();
		};

		struct Skin
		{
			BoneCollection vnBones;
			DeformationPtr pDeformation;

			Skin();
			~Skin();
		};

		struct Deformation
		{
			SkinCollection vnSkin;
			TripolyCollectionPtr pFaces;
			ControlPointCollectionPtr pControlPoints;

			Deformation();
			~Deformation();
		};

	public: 

		MeshContext();
		~MeshContext();

		ControlPointCollection vnControlPoints;
		TripolyCollection vnFaces;
		Deformation lDeformation;
		TexMap vnTextures;

		Eifersucht::Bool bPrecalcBinormals;
		Eifersucht::Bool bPrecalcTangents;

		Eifersucht::Bool bPolyGroupsAvailable;
		Eifersucht::Bool bNormalsAvailable;
		Eifersucht::Bool bColorsAvailable;
		Eifersucht::Bool bUVsAvailable;

	protected:

		void InternalRestart();
		void InternalRelease();

		virtual void ReleaseExternalResources(
			) override;

		ImplPtr m_pImpl;

	};
};